#ifndef __KERNELSPLIT_H
#define __KERNELSPLIT_H

code init(code x);
code fini(code x);

stratego code kernelsplit(code body)
{
  strategies
    main = <table-create>("globals");
           <table-put>("globals", "init", Compound([], []));
           <table-put>("globals", "fini", Compound([], []));
           <topdown(try(RemoveCompounds)); topdown(try(KernelSplit))>body;
           <MergeDeclarations>([<table-get>("globals", "init"),
                                <id>,
                                <table-get>("globals", "fini")]);
           map(\a -> AssignInit(CodeConst(a))\); \a -> ArrayInit(a)\; id

    delinits = map(try(delinits2))

   rules
    delinits2:
      Declaration2(d, i) -> Declaration2(d, <map(try(delinits3))>(i))

    delinits3:
      DeclInit(i, a) -> i

   strategies
    getinits  = filter(\Declaration2(d, i) -> i\); map(getinits2); concat
    getinits2 = filter(\DeclInit(IdDecl(a, i, b), AssignInit(c)) -> Stat(Assign(i, AssignEq, c))\)

  rules
    KernelSplit:
      Stat(FunCall(Id("init"), [CodeConst(i)])) ->
      Stat(EmptyExp)
      where (<table-put>("globals", "init", i))

    KernelSplit:
      Stat(FunCall(Id("fini"), [CodeConst(i)])) ->
      Stat(EmptyExp)
      where (<table-put>("globals", "fini", i))

    MergeDeclarations:
      [Compound(d1, c1), Compound(d2, c2), Compound(d3, c3)] ->
      [Compound(<delinits; map(try(KAddPromote))>d2, [Compound(d1, c1)]), Compound([], <concat>([<getinits>(d2), c2])), Compound(d3, c3)]


    KAddPromote:
      Declaration2(t@TypeSpec(a, b, c),i) ->
      Declaration2(DeclSpec([Promote], t), i)

    KAddPromote:
      Declaration2(DeclSpec(d, t), i) ->
      Declaration2(DeclSpec([Promote|d], t), i)
      
    RemoveCompounds:
      Compound([], [Compound(d, s)]) -> Compound(d, s)
}

#endif /* __KERNELSPLIT_H */
